package org.wu.reggie.service.impl;


import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.wu.reggie.dto.DishDto;
import org.wu.reggie.entity.*;
import org.wu.reggie.exception.LogicException;
import org.wu.reggie.mapper.CategoryMapper;
import org.wu.reggie.mapper.DishFlavorMapper;
import org.wu.reggie.mapper.DishMapper;
import org.wu.reggie.service.DishService;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class DishServiceImpl implements DishService {


    @Autowired(required = false)
    private DishMapper dishMapper;

    @Autowired(required = false)
    private DishFlavorMapper dishFlavorMapper;

    @Autowired(required = false)
    private CategoryMapper categoryMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 作用 查询菜品的分页列表
     *
     * @param page     当前页
     * @param pageSize 当前页面大小
     * @param name     查询菜品名字
     * @return
     */
    @Override
    public Page<DishDto> page(Integer page, Integer pageSize, String name) {
        // 1 设置当前页面与页面大小
        PageHelper.startPage(page, pageSize);

        // 2 查询数据 这里得到的是List<Dish>
        List<Dish> dishList = dishMapper.findByName(name);

        // 3 得到PageInfo，pageInfo对象里面存储的是Dish
        PageInfo<Dish> pageInfo = new PageInfo<>(dishList);

        // 4 得到分页数据的集合 然后遍历所有的Dish 然后把每一个Dish转换成DishDTO 并且添加到集合中
        // 这一步先省略
        ArrayList<DishDto> dishDtoList = new ArrayList<>();
        for (Dish dish : pageInfo.getList()) {
            DishDto dishDto = new DishDto();
            // 把dish的属性值拷贝到dishDto里面，
            // 什么时候可以使用属性拷贝 两个对象的属性名与类型都一致的情况下 那么就可以拷贝 如果不对应的属性则不拷贝
            BeanUtils.copyProperties(dish, dishDto);

            // 根据菜品的类别id查询类别
            Category category = categoryMapper.findById(dish.getCategoryId());

            dishDto.setCategoryName(category.getName());
            dishDtoList.add(dishDto);
        }


        // 5 将pageInfo对象封装成自己的page对象
        Page<DishDto> pageResult = new Page<>(dishDtoList, pageInfo.getTotal(), pageSize, page);

        return pageResult;
    }

    /**
     * 作用 保存菜品并且携带口味信息 (未完成实体类) 没有提交事务
     *
     * @param dishDto
     */
    // 这里没有提交事务 很有可能前端提示成功后后端数据没有添加到数据库
    @Override
    @Transactional
    public void saveWithFlavor(DishDto dishDto) {
        // 1 添加修改和创建的时间
        dishDto.setUpdateTime(LocalDateTime.now());
        dishDto.setCreateTime(LocalDateTime.now());
        dishDto.setSort(0);
        dishDto.setStatus(1);
        // 2 保存菜品
        dishMapper.save(dishDto); // 学习mybatis的时候 保存数据可以让主键列设置给当前的实体类对象
        // 3 补全口味的dish_id 创建时间 修改时间 创建人 修改人
        // 获取所有的口味信息
        List<DishFlavor> flavors = dishDto.getFlavors();
        // 遍历所有口味信息 补全dish_id 创建时间 修改时间 创建人 修改人
        List<DishFlavor> dishFlavorList = flavors.stream().map(flavor -> {
            flavor.setDishId(dishDto.getId());
            flavor.setCreateTime(LocalDateTime.now());
            flavor.setUpdateTime(LocalDateTime.now());
            flavor.setCreateUser(dishDto.getCreateUser());
            flavor.setUpdateUser(dishDto.getUpdateUser());
            return flavor;
        }).collect(Collectors.toList());

        // 4 批量保存口味信息
        dishFlavorMapper.saveBatch(dishFlavorList);

        // r1 由于菜品的数据已经发生改变了 那么需要情况缓存
        Set keys = redisTemplate.keys("dish_*");
        redisTemplate.delete(keys);
    }

    /**
     * 作用 根据id查询菜品和菜品的口味
     *
     * @param id 菜品的口味
     * @return
     */
    @Override
    public DishDto findById(Long id) {

        // 根据id 查询菜品的口味
        List<DishFlavor> dishFlavorList = dishFlavorMapper.findByDishId(id);

        // 根据id查询菜品
        Dish dish = dishMapper.findById(id);

        // 创建一个DishDto实体类封装查询到的数据
        DishDto dishDto = new DishDto();
        // 拷贝属性
        BeanUtils.copyProperties(dish, dishDto);
        dishDto.setFlavors(dishFlavorList);
        return dishDto;
    }

    /**
     * 修改菜品
     * @param dishDto 页面传递过来的参数包含菜品与口味
     */
    // 这里还是没有提交事务
    @Override
    @Transactional
    public void updateWithFlavor(DishDto dishDto) {
        // 1 补全修改时间
        dishDto.setUpdateTime(LocalDateTime.now());
        // 2 修改菜品
        dishMapper.updateById(dishDto);
        // 3 删除该菜品的所有口味信息
        dishFlavorMapper.deleteByDishId(dishDto.getId());

        // 4 补全口味信息 然后重新插入
        List<DishFlavor> flavors = dishDto.getFlavors();

        if (flavors.size()<=0){
            throw new LogicException("口味不能为空");
        }

        List<DishFlavor> dishFlavorList = flavors.stream().map(flavor -> {
            flavor.setDishId(dishDto.getId());
            flavor.setCreateTime(LocalDateTime.now());
            flavor.setUpdateTime(LocalDateTime.now());
            flavor.setCreateUser(dishDto.getCreateUser());
            flavor.setUpdateUser(dishDto.getUpdateUser());
            return flavor;
        }).collect(Collectors.toList());

        // 5 批量保存口味信息
        dishFlavorMapper.saveBatch(dishFlavorList);

        // r2 由于保存菜品的数据已经发生改变了 那么需要清空缓存
        Set keys = redisTemplate.keys("dish_*");
        redisTemplate.delete(keys);
    }

    /**
     * 方法作用 根据菜品类别的id查询的菜品
     * @param categoryId
     * @return
     */
    @Override
    public List<DishDto> findByCategoryId(Long categoryId,Integer status) {
        List<DishDto> dishDtoList = null;

        // r1 先查询redis 查看redis是否存在该类菜品
        // 拼接key
        String key = "dish_" + categoryId + "_" + status;
        dishDtoList = (List<DishDto>) redisTemplate.opsForValue().get(key);

        // r2 如果redis中不存在该类别的菜品 就查询数据库
        if (dishDtoList == null){
            List<Dish> dishList = dishMapper.findByCategoryId(categoryId,status);
            // 遍历所有dish 把dish转换为dto
            dishDtoList = dishList.stream().map(dish -> {
                DishDto dishDto = new DishDto();
                // 属性拷贝
                BeanUtils.copyProperties(dish, dishDto);
                // 查看该菜品的口味信息
                List<DishFlavor> dishFlavorList = dishFlavorMapper.findByDishId(dish.getId());
                dishDto.setFlavors(dishFlavorList);
                // 类别信息
                Category category = categoryMapper.findById(dish.getCategoryId());
                dishDto.setCategoryName(category.getName());
                return dishDto;
            }).collect(Collectors.toList());
            // r3 如果菜品是从数据库中查询出来的 那么必须要添加到缓存中 缓存保留一天
            redisTemplate.opsForValue().set(key,dishDtoList,60*24, TimeUnit.MINUTES);
        }
        return dishDtoList;
    }
}
